<?php
/** 
 * EGP Framework
 *
 * LICENSE
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @author     Akon(番茄红了) <aultoale@gmail.com>
 * @copyright  Copyright (c) 2008 (http://www.tblog.com.cn)
 * @license    http://www.gnu.org/licenses/gpl.html     GPL 3
 */

!defined('EGP_LIB_DIR') && die('Access Deny!');

/**
 * 财付通支付 (中介担保)
 *
 * @package    classes
 * @author     Akon(番茄红了) <aultoale@gmail.com>
 * @copyright  Copyright (c) 2008 (http://www.tblog.com.cn)
 * @license    http://www.gnu.org/licenses/gpl.html     GPL 3
 */
class EGP_Payment_Adapter_Tenpay_Mediate extends EGP_Payment_Adapter_Abstract
{

    /**
     * 支付方式参数
     *
     * @var array
     */
    protected $_config = array(
        'cmdno'             => 12,   //任务代码, 取定值 12
        'encode_type'       => 1,    //编码类型, 1:GB2312编码, 2:UTF-8编码
        'chnid'             => null, //平台提供者的财付通账号
        'seller'            => null, //收款方财付通账号
        'mch_name'          => null, //商品名称, 不能包含 <>'"% 特殊字符
        'mch_price'         => 0,    //商品总价, 单位为分
        'mch_desc'          => null, //交易说明, 不能包含 <>'"% 特殊字符
        'mch_type'          => 1,    //交易类型, 1:实物交易 2:虚拟交易
        'mch_vno'           => null, //商家定单号
        'mch_returl'        => null, //支付响应 URL
        'transport_desc'    => null, //物流公司或物流方式说明
        'transport_fee'     => 0,    //需买方另支付的物流费用, 单位为分
        'need_buyerinfo'    => 1,    //是否需要在财付通填定物流信息, 1:需要 2:不需要
        'show_url'          => null, //支付后的商户支付结果展示页面
        'attach'            => null, //商家数据包
        'key'               => null, //商家密钥
    );

    /**
     * 设置订单编号
     *
     * @param  string  $id
     * @return EGP_Payment_Adapter_Tenpay
     */
    public function setId($id)
    {
        $id = trim((string) $id);

        if (empty($id)) {
            throw new EGP_Exception('订单编号不能为空');
        }

        if (strlen($id) > 28) {
            throw new EGP_Exception('订单编号的长度不能大于 28');
        }

        $this->_config['mch_vno'] = $id;

        return $this;
    }

    /**
     * 设置订单主题
     *
     * @param  string  $subject
     * @return EGP_Payment_Adapter_Tenpay
     * @throws EGP_Exception
     */
    public function setSubject($subject)
    {
        $subject = str_break(trim(str_replace(array("'", '"', '%', '<', '>'), '', $subject)), 32);

        if (empty($subject)) {
            throw new EGP_Exception("商品名称不能为空");
        }

        $this->_config['mch_name'] = $subject;

        return $this;
    }

    /**
     * 设置订单总金额
     *
     * @param  float  $amount
     * @return EGP_Payment_Adapter_Tenpay
     */
    public function setAmount($amount)
    {
        if (empty($amount)) {
            throw new EGP_Exception('商品总价不能为空');
        }

        if (!$this->_isFloat($amount) || floatval($amount) <= 0) {
            throw new EGP_Exception('无效的商品总价');
        }

        $this->_config['mch_price'] = $amount;

        return $this;
    }

    /**
     * 设置业务代码
     *
     * 取定值: 12
     *
     * @param  integer  $cmdno
     * @return EGP_Payment_Adapter_Tenpay_Mediate
     */
    public function setCmdno($no)
    {
        return $this;
    }

    /**
     * 设置编码类型
     *
     * 1: GB2312编码 2: UTF-8编码
     *
     * @param  integer  $type
     * @return EGP_Payment_Adapter_Tenpay_Mediate
     */
    public function setEncodeType($type)
    {
        if ($type != 1 && $type != 2) {
            throw new EGP_Exception('无效的编码类型');
        }

        $this->_config['encode_type'] = (integer) $type;

        return $this;
    }

    /**
     * 设置平台提供者财付通帐号
     *
     * @param  string  $id
     * @return EGP_Payment_Adapter_Tenpay_Mediate
     * @throws EGP_Exception
     */
    public function setChnid($id)
    {
        $id = trim((string) $id);

        if (empty($id)) {
            throw new EGP_Exception('平台提供者财付通帐号不能为空');
        }

        if (preg_match('/^[1-9]\d{4,12}$/', $id) || $this->_isMail($id)) {
            $this->_config['chnid'] = $id;
        } else {
            throw new EGP_Exception('无效的平台提供者财付通帐号');
        }

        return $this;
    }

    /**
     * 设置收款方财付通帐号
     *
     * @param  string  $id
     * @return EGP_Payment_Adapter_Tenpay_Mediate
     * @throws EGP_Exception
     */
    public function setSeller($id)
    {
        $id = trim((string) $id);

        if (empty($id)) {
            throw new EGP_Exception('收款方财付通帐号不能为空');
        }

        if (preg_match('/^[1-9]\d{4,12}$/', $id) || $this->_isMail($id)) {
            $this->_config['seller'] = $id;
        } else {
            throw new EGP_Exception('无效的收款方财付通帐号');
        }

        return $this;
    }

    /**
     * 设置商品名称
     *
     * 不能包含 <>'"% 特殊字符
     *
     * @param  string  $name
     * @return EGP_Payment_Adapter_Tenpay_Mediate
     * @throws EGP_Exception
     */
    public function setMchName($name)
    {
        return $this->setSubject($name);
    }

    /**
     * 设置交易说明
     *
     * 不能包含 <>'"% 特殊字符
     *
     * @param  string  $desc
     * @return EGP_Payment_Adapter_Tenpay_Mediate
     * @throws EGP_Exception
     */
    public function setMchDesc($desc)
    {
        $desc = str_break(trim(str_replace(array("'", '"', '%', '<', '>'), '', $desc)), 64);

        if (empty($desc)) {
            throw new EGP_Exception("交易说明不能为空");
        }

        $this->_config['mch_desc'] = $desc;

        return $this;
    }

    /**
     * 设置商品总价
     *
     * @param  float  $price
     * @return EGP_Payment_Adapter_Tenpay_Mediate
     */
    public function setMchPrice($price)
    {
        return $this->setAmount($price);
    }

    /**
     * 设置交易类型
     *
     * 1: 实物交易 2: 虚拟交易
     *
     * @param  integer  $type
     * @return EGP_Payment_Adapter_Tenpay_Mediate
     */
    public function setMchType($type)
    {
        if ($type != 1 && $type != 2) {
            throw new EGP_Exception('无效的编码类型');
        }

        $this->_config['encode_type'] = (integer) $type;

        return $this;
    }

    /**
     * 设置商家订单号
     *
     * 此参数仅在对账时提供 YYYYMMDDXXXX
     *
     * @param  string  $no
     * @return EGP_Payment_Adapter_Tenpay_Mediate
     * @throws EGP_Exception
     */
    public function setMchVno($no)
    {
        return $this->setId($no);
    }

    /**
     * 设置支付响应 URL
     *
     * @param  string  $url
     * @return EGP_Payment_Adapter_Tenpay_Mediate
     * @throws EGP_Exception
     */
    public function setMchReturl($url)
    {
        if (empty($url)) {
            throw new EGP_Exception('支付响应 URL 地址不能为空');
        }

        if (!$this->_isUrl($url)) {
            throw new EGP_Exception('无效的支付响应 URL');
        }

        $this->_config['mch_returl'] = (string) $url;

        return $this;
    }

    /**
     * 设置物流公司或物流方式说明
     *
     * @param  string  $desc
     * @return EGP_Payment_Adapter_Tenpay_Mediate
     * @throws EGP_Exception
     */
    public function setTransportDesc($desc)
    {
        $desc = str_break(trim(strip_tags($desc)), 32);

        if (empty($desc)) {
            throw new EGP_Exception("物流公司或物流方式说明不能为空");
        }

        $this->_config['transport_desc'] = $desc;

        return $this;
    }

    /**
     * 需买方另支付的物流费用
     *
     * @param  float  $fee
     * @return EGP_Payment_Adapter_Tenpay
     */
    public function setTransportFee($fee)
    {
        if (!$this->_isFloat($fee) || floatval($fee) < 0) {
            throw new EGP_Exception('无效的物流费用');
        }

        $this->_config['transport_fee'] = $fee;

        return $this;
    }

    /**
     * 是否需要在财付通填定物流信息
     *
     * 1: 需要 2: 不需要
     *
     * @param  integer  $flag
     * @return EGP_Payment_Adapter_Tenpay_Mediate
     */
    public function setNeedBuyerinfo($flag)
    {
        if ($flag != 1 && $flag != 2) {
            throw new EGP_Exception('无效的编码类型');
        }

        $this->_config['need_buyerinfo'] = (integer) $flag;

        return $this;
    }

    /**
     * 设置支付后的商户支付结果展示页面 URL
     *
     * @param  string  $url
     * @return EGP_Payment_Adapter_Tenpay_Mediate
     * @throws EGP_Exception
     */
    public function setShowUrl($url)
    {
        if (empty($url)) {
            throw new EGP_Exception('支付结果展示页面 URL 地址不能为空');
        }

        if (!$this->_isUrl($url)) {
            throw new EGP_Exception('无效的支付结果展示页面 URL');
        }

        $this->_config['show_url'] = (string) $url;

        return $this;
    }

    /**
     * 设定商家数据包
     *
     * 数据包将按原样返回
     *
     * @param  string  $attach
     * @return EGP_Payment_Adapter_Tenpay
     * @throws EGP_Exception
     */
    public function setAttach($attach)
    {
        if (empty($attach)) {
            throw new EGP_Exception('商家数据包不能为空');
        }

        $this->_config['attach'] = (string) $attach;

        return $this;
    }

    /**
     * 设置商户密钥
     *
     * @param  string  $key
     */
    public function setKey($key)
    {
        if (empty($key)) {
            throw new EGP_Exception('商户密钥不能为空');
        }

        if (!is_string($key) || !preg_match('/[a-z0-9]{32}/i', $key)) {
            throw new EGP_Exception('无效的商户密钥');
        }

        $this->_config['key'] = (string) $key;

        return $this;
    }

    /**
     * 获取数字签名
     *
     * @return string
     */
    public function getSign()
    {
        extract($this->_config);
        $mch_price = $mch_price * 100;
        $transport_fee = $transport_fee * 100;
        if ($encode_type == 1) {
            $attach = iconv('utf-8', 'gbk', $attach);
            $mch_name = iconv('utf-8', 'gbk', $mch_name);
            $mch_desc = iconv('utf-8', 'gbk', $mch_desc);
            $transport_desc = iconv('utf-8', 'gbk', $transport_desc);
        }
        $signText = "attach=$attach&chnid=$chnid&cmdno=$cmdno&encode_type=$encode_type&" .
                    "mch_desc=$mch_desc&mch_name=$mch_name&mch_price=$mch_price&" .
                    "mch_returl=$mch_returl&mch_type=$mch_type&mch_vno=$mch_vno&" .
                    "need_buyerinfo=$need_buyerinfo&seller=$seller&show_url=$show_url&" .
                    "transport_desc=$transport_desc&transport_fee=$transport_fee&version=2";
        return strtoupper(md5("$signText&key=$key"));
    }

    /**
     * 获取支付网关地址
     *
     * @return string
     */
    public function getGateWay()
    {
        return 'https://www.tenpay.com/cgi-bin/med/show_opentrans.cgi';
    }

    /**
     * 获取支付 URL
     *
     * @return string
     */
    public function getPayUrl()
    {
        extract($this->_config);
        $mch_price = $mch_price * 100;
        $transport_fee = $transport_fee * 100;

        if ($encode_type == 1) {
            $attach = iconv('utf-8', 'gbk', $attach);
            $mch_name = iconv('utf-8', 'gbk', $mch_name);
            $mch_desc = iconv('utf-8', 'gbk', $mch_desc);
            $transport_desc = iconv('utf-8', 'gbk', $transport_desc);
        }

        $attach = urlencode($attach);
        $mch_name = urlencode($mch_name);
        $mch_desc = urlencode($mch_desc);
        $mch_returl = urlencode($mch_returl);
        $show_url = urlencode($show_url);
        $transport_desc = urlencode($transport_desc);

        $query = "attach=$attach&chnid=$chnid&cmdno=$cmdno&encode_type=$encode_type&" .
                 "mch_desc=$mch_desc&mch_name=$mch_name&mch_price=$mch_price&" .
                 "mch_returl=$mch_returl&mch_type=$mch_type&mch_vno=$mch_vno&" .
                 "need_buyerinfo=$need_buyerinfo&seller=$seller&show_url=$show_url&" .
                 "transport_desc=$transport_desc&transport_fee=$transport_fee&version=2";
        return $this->getGateWay() . '?' . $query . '&sign=' . $this->getSign();
    }

}